package cn.cyh.queue_service.config.security;

import io.jsonwebtoken.*;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;

import javax.crypto.SecretKey;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.stream.Collectors;

/**
 * JWT令牌提供者
 */
@Component
@Slf4j
public class JwtTokenProvider {

    @Value("${jwt.secret}")
    private String jwtSecret;

    @Value("${jwt.expiration}")
    private long jwtExpirationInSeconds;

    @Value("${jwt.header}")
    private String jwtHeader;

    @Value("${jwt.token-prefix}")
    private String jwtTokenPrefix;

    /**
     * 从JWT密钥创建签名密钥
     */
    private SecretKey getSigningKey() {
        byte[] keyBytes = Decoders.BASE64.decode(jwtSecret);
        // 检查密钥长度
        if (keyBytes.length * 8 < 256) {
            log.warn("JWT密钥长度不足256位，当前长度: {}位", keyBytes.length * 8);
            // 可以考虑在开发环境下自动扩展密钥长度
            byte[] extendedKey = new byte[32]; // 256位 = 32字节
            System.arraycopy(keyBytes, 0, extendedKey, 0, Math.min(keyBytes.length, extendedKey.length));
            // 填充剩余空间
            for (int i = keyBytes.length; i < extendedKey.length; i++) {
                extendedKey[i] = (byte)(i % 256);
            }
            keyBytes = extendedKey;
            log.info("已自动扩展JWT密钥长度至256位");
        }
        return Keys.hmacShaKeyFor(keyBytes);
    }

    /**
     * 生成JWT令牌
     */
    public String generateToken(Authentication authentication) {
        String authorities = authentication.getAuthorities().stream()
                .map(GrantedAuthority::getAuthority)
                .collect(Collectors.joining(","));

        Date now = new Date();
        Date validity = new Date(now.getTime() + jwtExpirationInSeconds * 1000);

        return Jwts.builder()
                .subject(authentication.getName())
                .claim("auth", authorities)
                .issuedAt(now)
                .expiration(validity)
                .signWith(getSigningKey())
                .compact();
    }
    
    /**
     * 根据用户名和角色创建令牌
     * 
     * @param username 用户名
     * @param role 角色
     * @return JWT令牌
     */
    public String createToken(String username, String role) {
        Date now = new Date();
        Date validity = new Date(now.getTime() + jwtExpirationInSeconds * 1000);

        return Jwts.builder()
                .subject(username)
                .claim("auth", role)
                .issuedAt(now)
                .expiration(validity)
                .signWith(getSigningKey())
                .compact();
    }

    /**
     * 从JWT令牌获取认证信息
     */
    public Authentication getAuthentication(String token) {
        // 在0.12.5版本中，我们使用更简单的方式解析JWT
        Jws<Claims> claimsJws = Jwts.parser()
                .verifyWith(getSigningKey())
                .build()
                .parseSignedClaims(token);
                
        Claims claims = claimsJws.getPayload();

        Collection<? extends GrantedAuthority> authorities =
                Arrays.stream(claims.get("auth").toString().split(","))
                        .map(SimpleGrantedAuthority::new)
                        .collect(Collectors.toList());

        UserDetails principal = new User(claims.getSubject(), "", authorities);

        return new UsernamePasswordAuthenticationToken(principal, token, authorities);
    }

    /**
     * 验证JWT令牌
     */
    public boolean validateToken(String token) {
        if (token == null) {
            log.error("JWT令牌为空");
            return false;
        }
        
        try {
            // 移除可能存在的额外空格，确保token格式正确
            token = token.trim();
            
            Jwts.parser()
                    .verifyWith(getSigningKey())
                    .build()
                    .parseSignedClaims(token);
            return true;
        } catch (MalformedJwtException e) {
            log.error("无效的JWT令牌: {}", e.getMessage());
        } catch (ExpiredJwtException e) {
            log.error("JWT令牌已过期: {}", e.getMessage());
        } catch (UnsupportedJwtException e) {
            log.error("不支持的JWT令牌: {}", e.getMessage());
        } catch (IllegalArgumentException e) {
            log.error("JWT令牌格式错误: {}", e.getMessage());
        } catch (Exception e) {
            log.error("JWT令牌验证失败: {}", e.getMessage());
        }
        return false;
    }
    
    /**
     * 从令牌获取用户名
     */
    public String getUsernameFromToken(String token) {
        Jws<Claims> claimsJws = Jwts.parser()
                .verifyWith(getSigningKey())
                .build()
                .parseSignedClaims(token);
                
        return claimsJws.getPayload().getSubject();
    }
    
    /**
     * 获取JWT令牌的过期时间（毫秒）
     */
    public Long getExpirationTime() {
        return jwtExpirationInSeconds * 1000;
    }
    
    /**
     * 获取JWT令牌的有效期（毫秒）
     * 
     * @return 有效期毫秒数
     */
    public Long getValidityInMilliseconds() {
        return jwtExpirationInSeconds * 1000;
    }
} 